using System;
using System.Linq;
using ET;
using PEDEngine;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace PEDEngine
{
    public class OnPUGUIClick : UnityEvent<PointerEventData>
    {
    }

    public class OnPUGUIMouseDown : UnityEvent<PointerEventData>
    {
    }

    public class OnPUGUIMouseUp : UnityEvent<PointerEventData>
    {
    }

    public class OnPUGUIMouseLongPress : UnityEvent<GameObject>
    {
    }

    public class OnPUGUIBeginDrag : UnityEvent<PointerEventData>
    {
    }

    public class OnPUGUIDrag : UnityEvent<PointerEventData>
    {
    }

    public class OnPUGUIEndDrag : UnityEvent<PointerEventData>
    {
    }

    public class OnPUGUIExit : UnityEvent<PointerEventData>
    {
    }

    public class OnPUGUIEnter : UnityEvent<PointerEventData>
    {
    }
}

public class PUGUIListener : MonoBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler,
    IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerExitHandler, IPointerEnterHandler
{
    public OnPUGUIClick OnClick = new OnPUGUIClick();
    public OnPUGUIMouseDown OnMouseDown = new OnPUGUIMouseDown();
    public OnPUGUIMouseUp OnMouseUp = new OnPUGUIMouseUp();
    public OnPUGUIMouseLongPress OnLongMousePress = new OnPUGUIMouseLongPress();
    public OnPUGUIBeginDrag onBeginDrag = new OnPUGUIBeginDrag();
    public OnPUGUIDrag onDrag = new OnPUGUIDrag();
    public OnPUGUIEndDrag onEndDrag = new OnPUGUIEndDrag();
    public OnPUGUIExit OnExit = new OnPUGUIExit();
    public OnPUGUIEnter OnEnter = new OnPUGUIEnter();

    //  public Action onLongMousePressAction;

    /// <summary>
    /// 是否开始检查点击的开关
    /// </summary>
    private bool isPress;

    private float timer = 0;
    private const float longPressTime = 1f;
    private float longPressStartTime = 0;
    private bool isPrecision = true;
    private Vector3 offset;

    private RectTransform m_rt;

//是否长按中
    private bool isLongPress;
    private bool isCanDrag;
    private Action<GameObject, GameObject> onCollision;
    private Vector2 stratPos;
    private bool reset;
    private bool isLong;

    /// <summary>
    /// 是否和长按互斥
    /// </summary>
    public bool IsOutLongPress
    {
        set { isLong = value; }
    }

    private void Awake()
    {
        m_rt = gameObject.GetComponent<RectTransform>();
    }


    private void Update()
    {
        if (isPress && OnLongMousePress != null)
        {
            timer += Time.deltaTime;
            if (timer- longPressStartTime >= longPressTime)
            {
                isLongPress = true;
                OnLongMousePress?.Invoke(gameObject);
                isPress = false;
                
                timer=0;
            }
        }

        // if (isLongPress)
        // {
        //     isLongPress = false;
        //     onLongMousePressAction?.Invoke();
        // }
    }

    /// <summary>
    /// 开启碰撞拖拽  webporiect 专属   以后其他地方有需求在更改或者重写
    /// </summary>
    /// <param name="tags">UI碰撞检测的tag</param>
    public void EnableCollisionDrag(Action<GameObject, GameObject> onCollision, bool reset = true)
    {
        isCanDrag = true;

        this.onCollision = onCollision;
        this.reset = reset;
    }


    public void DisEnableCollisionDrag()
    {
        isCanDrag = false;
        onCollision = null;
    }

//单击
    public void OnPointerClick(PointerEventData eventData)
    {
        OnClick?.Invoke(eventData);
    }

//按下
    public void OnPointerDown(PointerEventData eventData)
    {
        OnMouseDown?.Invoke(eventData);
        isPress = true;
    }

    //抬起
    public void OnPointerUp(PointerEventData eventData)
    {
        if (!isLong)
            OnMouseUp?.Invoke(eventData);
        else
        {
            if(!isLongPress)
                OnMouseUp?.Invoke(eventData);
        }
        
        isPress = false;
        isLongPress = false;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        onBeginDrag?.Invoke(eventData);
        if (isCanDrag)
        {
            stratPos = m_rt.position;
            //如果精确拖拽则进行计算偏移量操作
            if (isPrecision)
            {
                // 存储点击时的鼠标坐标
                Vector3 tWorldPos;
                //UI屏幕坐标转换为世界坐标
                RectTransformUtility.ScreenPointToWorldPointInRectangle(m_rt, eventData.position,
                    eventData.pressEventCamera, out tWorldPos);
                //计算偏移量   
                offset = transform.position - tWorldPos;
            }
            //否则，默认偏移量为0
            else
            {
                offset = Vector3.zero;
            }

            SetDraggedPosition(eventData, false);
        }
    }


    public void OnDrag(PointerEventData eventData)
    {
        onDrag.Invoke(eventData);
        if (isCanDrag)
        {
            gameObject.GetComponent<Image>().raycastTarget = false;
            SetDraggedPosition(eventData, false);
        }
    }


    public void OnEndDrag(PointerEventData eventData)
    {
        if (isCanDrag)
        {
            SetDraggedPosition(eventData, true);
        }
    }

    /// <summary>
    /// 设置图片位置方法
    /// </summary>
    /// <param name="eventData"></param>
    private void SetDraggedPosition(PointerEventData eventData, bool isEndDrag)
    {
        isPress = false;
        //存储当前鼠标所在位置
        Vector3 globalMousePos;


        //UI屏幕坐标转换为世界坐标
        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(m_rt, eventData.position,
                eventData.pressEventCamera, out globalMousePos))
        {
            //设置位置及偏移量
            m_rt.position = globalMousePos + offset;
        }

        if (isEndDrag)
        {
            GameObject go = eventData.pointerCurrentRaycast.gameObject;
            if (reset)
            {
                m_rt.position = stratPos;
            }

            onCollision?.Invoke(go, gameObject);
            gameObject.GetComponent<Image>().raycastTarget = true;
        }
    }

    //移出指定范围
    public void OnPointerExit(PointerEventData eventData)
    {
        OnExit.Invoke(eventData);
    }

    //移入指定范围
    public void OnPointerEnter(PointerEventData eventData)
    {
        OnEnter.Invoke(eventData);
    }
}